from Libs import const
import numpy as np
from CenterServer.Models import cell


class Player():
    speed = 1

    Room = None
    Map = None

    def __init__(self, mail, name, room):
        self.mail = mail
        self.name = name

        self.active = False

        self.score = 0
        self.direction = 0
        self.cellTypeId = 104

        self.Room = room
        self.Map = room.mapArray
        self.currentCell = None
        self.allTrackCells = []
        self.allManorCells = []

        self.moveDistance = 0
        self.position = [0, 0, 0]

        self.trackStart = False
        self.trackStartFrom = None

        self.bottomLeft = [0, 0]
        self.topRight = [0, 0]

    def initManors(self):
        self.currentCell = self.Room.getBornCell()
        for i in range(self.currentCell.x, self.currentCell.x + 3):
            for j in range(self.currentCell.y, self.currentCell.y + 3):
                self.Room.setManor(i, j, self.mail, False)

        self.position = [self.currentCell.x, -0.5, self.currentCell.y]

    def update(self, timeInterval):
        if self.direction == 0:
            return
        dirArray = self.dirToVector(self.direction)
        direction = np.array(dirArray, dtype=np.float)
        currentPos = np.array(self.position, dtype=np.float)
        velocity = direction * self.speed * const.MoveSpeed
        currentPos += velocity * timeInterval
        self.position = currentPos.__array__()

        moveDistance = self.speed * const.MoveSpeed * timeInterval
        self.moveDistance += moveDistance
        while self.moveDistance >= const.CellWidth:
            self.moveDistance -= const.CellWidth
            self.arriveGrid()

    def arriveGrid(self):
        arrived = None
        if self.direction == 1:
            arrived = self.Map[self.currentCell.x][self.currentCell.y + 1]
        elif self.direction == 2:
            arrived = self.Map[self.currentCell.x - 1][self.currentCell.y]
        elif self.direction == 3:
            arrived = self.Map[self.currentCell.x][self.currentCell.y - 1]
        elif self.direction == 4:
            arrived = self.Map[self.currentCell.x + 1][self.currentCell.y]

        if arrived is None:
            return

        if not self.trackStart:
            if not self.isMyGround(arrived):
                self.trackStart = True
                self.trackStartFrom = self.currentCell

        if self.trackStart:
            normalTrack = False
            if self.isMyGround(arrived):
                if self.isMyGround(self.trackStartFrom):
                    self.testAndFill()
                self.clearTracks()
            elif self.isMyTrack(arrived):
                normalTrack = True
            elif arrived.cellType == cell.CellType.Border:
                pass
            else:
                normalTrack = True

            if normalTrack:
                flag = self.directionToFlag(self.direction)
                self.Room.setTrack(arrived.x, arrived.y, self.mail, flag)
                self.allTrackCells.append(arrived)

        self.setCurrentCell(arrived)
        self.position = [arrived.x, -0.5, arrived.y]

    def setCurrentCell(self, arrived):
        self.currentCell = arrived
        self.currentCell.tracker = self.mail

        if arrived.x < self.bottomLeft[0]:
            self.bottomLeft[0] = arrived.x
        elif arrived.x > self.topRight[0]:
            self.topRight[0] = arrived.x

        if arrived.y < self.bottomLeft[1]:
            self.bottomLeft[1] = arrived.y
        elif arrived.y > self.topRight[1]:
            self.topRight[1] = arrived.y

    def dirToVector(self, direction):
        if direction == 1:
            return [0, 0, 1]
        elif direction == 2:
            return [-1, 0, 0]
        elif direction == 3:
            return [0, 0, -1]
        elif direction == 4:
            return [1, 0, 0]
        else:
            return [0, 0, 0]

    def isMyGround(self, arrived):
        return arrived.owner == self.mail

    def isMyTrack(self, arrived):
        return arrived.tracker == self.mail

    def IsCanFill(self, arrived):
        return not self.isMyGround(arrived) and not self.isMyTrack(arrived)

    def testAndFill(self):
        testMap = [[0]*self.Room.width for i in range(self.Room.height)]

        self.HorizontalTest(testMap)
        self.VerticalTest(testMap)
        SeedClosedFlags = self.SeedTest(testMap)
        self.FillGrids(testMap, SeedClosedFlags)

    def HorizontalTest(self, testMap):
        for y in range(self.bottomLeft[1], self.topRight[1] + 1):
            points = []
            groundIndex = -1
            for x in range(self.bottomLeft[0], self.topRight[0] + 1):
                grid = self.Map[x][y]
                if self.isMyTrack(grid) and self.IsHorizontalPoint(grid):
                    points.append(grid)
                elif groundIndex == -1 and self.isMyGround(grid):
                    groundIndex = len(points)

            count = len(points)
            if count % 2 != 0:
                if groundIndex == -1:
                    continue

                linkPoint, linkGround = None, None
                if groundIndex % 2 != 0:
                    linkPoint = points[groundIndex - 1]
                    linkGround = self.FindGround(linkPoint.x, linkPoint.y, 1, 0)
                else:
                    linkPoint = points[groundIndex]
                    linkGround = self.FindGround(linkPoint.x, linkPoint.y, -1, 0)
                points.insert(groundIndex, linkGround)

            for i in range(0, count, 2):
                self.HorizontalLink(testMap, points[i], points[i + 1])

    def IsHorizontalPoint(self, arrived):
        return arrived.trackFlag == cell.TrackFlag.VerticalTrack

    def FindGround(self, x, y, dx, dy):
        x += dx
        y += dy
        while self.bottomLeft[0] <= x <= self.topRight[0] and \
                self.bottomLeft[1] <= y <= self.topRight[1]:
            grid = self.Map[x][y]
            if self.isMyGround(grid):
                return grid
            x += dx
            y += dy
        print("找不到我的地盘", x, y)
        return None

    def HorizontalLink(self, testMap, gridA, gridB):
        for x in range(gridA.x + 1, gridB.x):
            grid = self.Map[x][gridA.y]
            if self.IsCanFill(grid):
                testMap[grid.x][grid.y] = 1

    def VerticalTest(self, testMap):
        for x in range(self.bottomLeft[0], self.topRight[0] + 1):
            points = []
            groundIndex = -1
            for y in range(self.bottomLeft[1], self.topRight[1] + 1):
                grid = self.Map[x][y]
                if self.isMyTrack(grid) and self.IsVerticalPoint(grid):
                    points.append(grid)
                elif groundIndex == -1 and self.isMyGround(grid):
                    groundIndex = len(points)

            count = len(points)
            if count % 2 != 0:
                if groundIndex == -1:
                    continue

                linkPoint, linkGround = None, None
                if groundIndex % 2 != 0:
                    linkPoint = points[groundIndex - 1]
                    linkGround = self.FindGround(linkPoint.x, linkPoint.y, 0, 1)
                else:
                    linkPoint = points[groundIndex]
                    linkGround = self.FindGround(linkPoint.x, linkPoint.y, 0, -1)
                points.insert(groundIndex, linkGround)

            for i in range(0, count, 2):
                self.HorizontalLink(testMap, points[i], points[i + 1])

    def IsVerticalPoint(self, grid):
        return grid.trackFlag == cell.TrackFlag.HorizontalTrack

    def VerticalLink(self, testMap, gridA, gridB):
        for y in range(gridA.y + 1, gridB.y):
            grid = self.Map[gridA.x][y]
            if self.IsCanFill(grid):
                testMap[grid.x][grid.y] = 1

    def SeedTest(self, testMap):
        CurrentSeedFlag = 2
        SeedClosedFlags = []
        for y in range(self.bottomLeft[1] + 1, self.topRight[1]):
            for x in range(self.bottomLeft[0] + 1, self.topRight[0]):
                if testMap[x][y] == 1:
                    grid = self.Map[x][y]
                    if self.SeedFill(testMap, CurrentSeedFlag, grid) is False:
                        CurrentSeedFlag += 1
                        continue
                    SeedClosedFlags.append(CurrentSeedFlag)
                    CurrentSeedFlag += 1
        return SeedClosedFlags

    def SeedFill(self, testMap, CurrentSeedFlag, arrived):
        if testMap[arrived.x][arrived.y] == CurrentSeedFlag:
            return True
        if arrived.x == self.bottomLeft[0] or arrived.x == self.topRight[0] \
                or arrived.y == self.bottomLeft[1] \
                or arrived.y == self.topRight[1]:
            return False

        testMap[arrived.x][arrived.y] = CurrentSeedFlag

        for i in range(4):
            x = arrived.x + const.Direction4[i][0]
            y = arrived.y + const.Direction4[i][1]
            grid = self.Map[x][y]
            if self.IsCanFill(grid):
                if self.SeedFill(testMap, CurrentSeedFlag, grid) is False:
                    return False

        return True

    def FillGrids(self, testMap, SeedClosedFlags):
        for grid in self.allTrackCells:
            self.Room.setManor(grid.x, grid.y, self.mail)

        for y in range(self.bottomLeft[1] + 1, self.topRight[1]):
            for x in range(self.bottomLeft[0] + 1, self.topRight[0]):
                flag = testMap[x][y]
                if flag >= 2 and flag in SeedClosedFlags:
                    self.Room.setManor(x, y, self.mail)

    def clearTracks(self):
        self.trackStart = False
        self.trackStartFrom = None
        self.allTrackCells = []

    def directionToFlag(self, direction):
        return cell.TrackFlag.HorizontalTrack if self.isHorizontal(direction) \
                else cell.TrackFlag.VerticalTrack

    def isHorizontal(self, direction):
        return direction == 2 or direction == 4

    def isVertical(self, direction):
        return direction == 1 or direction == 3
